OilTrack · ตู้คีออสก์ที่หัวจ่าย (Gateway kiosk state machine)
Prototype V.2 · 2026-09
Spheresoft Co., Ltd.
เอกสารอ้างอิงต้นแบบ — ไม่ใช่สัญญาส่งมอบ
OilTrack · ตู้คีออสก์ที่หัวจ่าย
จอที่ติดตั้งอยู่กับหัวจ่ายจริง ทำหน้าที่เดียว: บอกคนที่ยืนอยู่หน้าตู้ว่าตอนนี้หัวจ่ายนี้อยู่ในสถานะอะไร และต้องทำอะไรต่อ ตู้ไม่รับการกดใด ๆ — ทุกการตัดสินใจเกิดในแอปคนขับหรือที่หลังบ้าน เอกสารนี้อธิบาย 11 สถานะ ลำดับความสำคัญที่ใช้เลือกสถานะ กฎของมาตรวัด และวิธีทดสอบทุกสถานะ
อ่านคู่กับ Doc - Business Flow (§1 และ §3 อธิบายฝั่งคนขับและบัญชีของเหตุการณ์เดียวกัน) และ Doc - Overview (§7 ตารางกำหนดเวลา)
1 · อุปกรณ์และการวางองค์ประกอบ
จอ 7 นิ้ว 1024 × 600 พิกเซล คงที่ ขับด้วยคอมพิวเตอร์บอร์ดเดียว ไม่มีการเลื่อนจอในทุกสถานะ ทุกอย่างต้องพอดีในกรอบนี้เสมอ แม้หัวจ่ายจะมีหัวจ่ายย่อย 1–4 หัว คนขับยืนห่างประมาณหนึ่งช่วงแขนกลางแดด ตัวอักษรจึงไม่เล็กกว่า 13px และตัวเลขหลักของแต่ละสถานะอยู่ที่ 54–104px
OilTrack
Gateway
DP-0005
หัวจ่ายลานจอด 2
state chip
09:41 · 02:41 UTC
main panel · flex 1
เนื้อหาของสถานะปัจจุบัน — QR + รหัส, การ์ดคำขอ, เลขหัวจ่ายย่อย, มาตรวัดสด หรือใบสรุป · padding 24–32px
info rail · 280px
หัวจ่ายนี้คือหัวไหน · ประจำที่หรือบนรถ · สถานี/ทะเบียน · เลข gateway · ชนิดน้ำมันที่จ่ายได้ · ตารางหัวจ่ายย่อยพร้อมจุดสถานะ
NET · SRV 34ms · TUN 10.8.0.14 · UTC 02:41:07Z · UP 14:22 · GW-1001 · FW 1.4.2 · STATE idle
รูปที่ 1 — โครงจอสี่แถบ หัวแถบ 52px · เนื้อหา · แถบข้อมูลด้านขวา 280px · แถบดีบัก 34px ที่แสดงทุกสถานะ ไม่มีสถานะใดซ่อนแถบนี้ เพราะช่างต้องอ่านค่าเชื่อมต่อได้ทันทีที่เดินถึงตู้
แถบข้อมูลด้านขวาตอบคำถามเดียวเสมอว่า “ผมยืนอยู่ที่หัวจ่ายไหน” — ลำดับคือ ตำแหน่งติดตั้ง (สถานีประจำที่ / รถน้ำมันเคลื่อนที่ + ทะเบียน) · สถานีหรือตัวรถ · เลข gateway · ชนิดน้ำมันที่หัวนี้จ่ายได้ · แล้วจึงเป็นหัวจ่ายย่อยเรียงตามลำดับเป็นตาราง 2×2 พร้อมจุดสถานะ (เขียว = ว่าง, น้ำเงิน = กำลังใช้งาน) สถานะ “กำลังใช้งาน” มาจากเลขหัวจ่ายย่อยของคำขอที่ถืออยู่ ไม่ใช่จากตัวล็อกเอง
2 · สถานะทั้ง 11 และเส้นทางเปลี่ยนสถานะ
→
#1 idle
QR 21×21 + รหัส 6 หลัก · วงแหวน 30 วินาที · คำแนะนำ 3 ขั้น
#8 locked
ปิดจ่ายจากส่วนกลาง
#9 error
ไม่มีลิงก์ไปส่วนกลาง — ไม่แสดง QR
สแกน/กรอกรหัส
↓
#2 binding
การ์ดคำขอ + นับถอยหลัง 2 นาที · ยืนยันในแอป
→
#3 bound
เลขหัวจ่ายย่อย 64px · นับถอยหลัง 5 นาที · แดงเมื่อเหลือไม่ถึงนาที
→
#4 progress
มาตรวัดสด 104px · อัตราไหล · เวลาที่ใช้
หมดเวลา / ถูกยกเลิก
↓
#2 หมดเวลา → กลับ #1
คำขอถอยเป็น อนุมัติแล้ว · ปลดหัวจ่าย
#3 หมดเวลา → #1
คำขอถูกยกเลิก · ปลดหัวจ่าย
#6 aborted
ถูกดึงกลางคัน · เหตุผลและผู้สั่ง · ค้าง 8 วินาที → #1
จ่ายจบ
↓
#5 complete
ลิตรจริง 84px · ผลต่างกับที่อนุมัติ · ใบยืนยันการส่งข้อมูล · ค้าง 10 วินาที → #1
#7 degraded
ไม่ใช่หน้าจอ — เป็นป้ายสีเหลืองบน #2/#3/#4 เมื่อลิงก์หลุด จ่ายต่อได้
#10 recovery
ไฟดับกลางการจ่าย · ปิดที่เลขมาตรวัดล่าสุด · ตั้งธง
รูปที่ 2 — เส้นทางเปลี่ยนสถานะ กรอบน้ำเงินคือเส้นทางปกติ #1 → #2 → #3 → #4 → #5 สถานะที่เหลือคือทางแยกที่เกิดจากเงื่อนไขจริง ไม่ใช่การกดข้ามหน้า
| # |
คีย์ |
เข้าเมื่อ |
ออกเมื่อ |
ตัวเลขหลักบนจอ |
| 0 | boot | เปิดเครื่อง / รีบูต | ตรวจครบ 6 ข้อ แล้วแตกไปตามเงื่อนไขจริง | แถบความคืบหน้าแบบกำหนดค่าได้ |
| 1 | idle | หัวจ่ายว่าง เปิดจ่าย และมีลิงก์ | มีคำขอมาจองหัวจ่าย | รหัส 6 หลัก (mono) |
| 2 | binding | สแกน QR หรือกรอกรหัสถูก | ยืนยันในแอป → #3 · ครบ 2 นาที → #1 | เวลาที่เหลือ |
| 3 | bound | คนขับยืนยันการผูกในแอป | เริ่มจ่าย → #4 · ครบ 5 นาที → คำขอถูกยกเลิก | เลขหัวจ่ายย่อย 64px |
| 4 | progress | มาตรวัดเริ่มเดิน | ถึงเพดาน หรือหยุดจ่ายครบ 1 นาที → #5 | ลิตรสด 104px |
| 5 | complete | คำขอปิดด้วยลิตรจริง | ค้าง 10 วินาที → #1 | ลิตรจริง 84px |
| 6 | aborted | คำขอถูกยกเลิก/ปลดขณะจองหรือผูกอยู่ | ค้าง 8 วินาที → #1 | เหตุผล + ผู้สั่ง |
| 7 | — | ลิงก์ไปส่วนกลางหลุดขณะมีงานอยู่ | ลิงก์กลับมา | ป้ายเหลือง + จำนวนรายการที่รอส่ง |
| 8 | locked | ผู้ดูแลระบบปิดการจ่ายของหัวนี้ | เปิดการจ่ายอีกครั้ง | ข้อความปิดการจ่าย |
| 9 | error | ตู้ว่างและไม่มีลิงก์ | ลิงก์กลับมา → #1 | ไม่มี QR — จงใจ |
| 10 | recovery | ร่องรอยในเครื่องตรงกับคำขอที่ถืออยู่ หลังรีสตาร์ต | ปิดคำขอที่เลขล่าสุด แล้วกลับ #1 | ลิตรล่าสุดที่วัดได้ |
ตารางที่ 1 — เงื่อนไขเข้า-ออกของทุกสถานะ #7 ไม่ใช่หน้าจอแยก จึงไม่มีคีย์ของตัวเอง
3 · ลำดับความสำคัญในการเลือกสถานะ
ตู้ไม่ได้ “ย้ายสถานะ” ตามเหตุการณ์ แต่คำนวณสถานะใหม่ทุกครั้ง จากสภาพจริง ณ ขณะนั้น ลำดับด้านล่างสำคัญทุกบรรทัด กฎแรกที่ตรงคือสถานะที่แสดง
1#10 recoveryมีร่องรอยการจ่ายที่ค้างและตรงกับคำขอที่หัวนี้ถืออยู่
2#4 → #2 → #3มีงานที่ยังมีชีวิตอยู่บนหัวนี้ (กำลังจ่าย ก่อน รอยืนยัน ก่อน ผูกแล้ว)
3#5 completeมีใบสรุปที่ยังอยู่ในช่วง 10 วินาที
4#6 abortedมีประกาศการยกเลิกที่ยังอยู่ในช่วง 8 วินาที
5#9 errorไม่มีลิงก์ไปส่วนกลาง
6#8 lockedหัวนี้ถูกปิดการจ่ายจากส่วนกลาง
7#1 idleไม่เข้าเงื่อนไขใดข้างบน — พร้อมรับการสแกน
รูปที่ 3 — ลำดับใน resolveState() งานที่มีชีวิตอยู่สำคัญกว่าทั้งลิงก์และการล็อก
เหตุผลที่ลำดับต้องเป็นแบบนี้: ถ้าลิงก์มาก่อนงาน ตู้จะตกไป #9 ทั้งที่น้ำมันกำลังไหล — คนหน้าตู้จะไม่เห็นมาตรวัดของตัวเอง ระบบจึงเลือกลดระดับเป็นป้าย #7 แทน และถ้าการล็อกมาก่อนงาน การสั่งปิดจ่ายกลางคันจะบังหน้าจอที่กำลังจ่าย หรือกลืนใบสรุป #5 หายไป การปิดจ่ายจึงมีผลกับการผูกครั้งใหม่เท่านั้น
4 · กฎของมาตรวัด
ลิตรเดินเมื่อไร
เดินเฉพาะตอนที่สถานะที่คำนวณได้คือ #4 เท่านั้น ไม่มีการเดินอยู่เบื้องหลังหน้าจออื่น เปิดหน้าจอทิ้งไว้แล้วตัวเลขจะไม่ไหลไปเอง
เพดานลิตร
ใช้ลิตรที่อนุมัติ ถ้าไม่มีใช้ลิตรที่ขอ คำขอแบบเต็มถังก็มีเพดาน — ระบบบังคับใช้แต่ไม่แสดง และไม่แสดงความจุถังเป็นตัวเลขในทุกกรณี
การจ่ายที่ตู้นี้ไม่ได้เริ่ม
รับมาที่เลขที่มาตรวัดรายงาน และปล่อยไว้ที่ #1 พร้อมหมายเหตุ “เริ่มก่อนหน้านี้” — การเปิดหน้าจอต้องไม่ไล่คำขอของคนอื่นไปจนจบ
ร่องรอยสำหรับกู้คืน
ระหว่างจ่าย ตู้เขียน {reqId, litres, at} ลงเครื่องทุก 2 วินาที และล้างเมื่อขึ้น #5 หรือถูกยกเลิก · #10 เกิดเฉพาะเมื่อร่องรอยตรงกับคำขอที่ถืออยู่ การโหลดหน้าเปล่า ๆ ไม่ทำให้กู้คืน
ตารางที่ 2 — สี่กฎที่กันไม่ให้ตัวเลขลิตรเพี้ยน ทั้งสี่ข้อเป็นข้อบังคับ ไม่ใช่การปรับแต่ง
5 · การบังคับเวลาสองทาง
ตู้บังคับเวลาสด เพราะเป็นเจ้าของหน้าจอ ส่วน DB.sync() เป็นตัวสำรองสำหรับตู้ที่ออฟไลน์ รีบูต หรือไม่ได้เปิดอยู่ ทั้งสองทางเรียกฟังก์ชันชุดเดียวกันจึงให้ผลตรงกัน — ไม่มีกรณีที่ “ตู้ว่าแบบหนึ่ง หลังบ้านว่าอีกแบบ”
ตู้เปิดอยู่
นับถอยหลังบนจอถึง 0 → ตู้เรียกฟังก์ชันปล่อย/ยกเลิกทันที คนที่ยืนอยู่เห็นผลในวินาทีนั้น
ตู้ไม่ได้เปิด / ออฟไลน์
รอบกวาดของหน้าอื่นที่เปิดอยู่ (ทุก 60 วินาที) ทำสิ่งเดียวกัน คำขอไม่ค้างล็อกรถทิ้งไว้แม้ไม่มีใครเปิดตู้
ข้อยกเว้นที่ตั้งใจ: แถวข้อมูลตัวอย่างที่สถานะ bound โดยไม่มีกำหนดเวลาเริ่มเติม และแถว binding ที่ไม่มีกำหนดเวลายืนยัน จะถูกข้ามโดยรอบกวาด และจอจะไม่แสดงนับถอยหลัง แถบเวลา หรือคำเตือน — ไม่ใช่แสดง 0:00 ค้างไว้ การตั้งเวลาให้แถวเหล่านี้เป็นการกระทำที่ต้องสั่งเอง
รูปที่ 4 — การบังคับเวลาสองทางและข้อยกเว้นของข้อมูลตัวอย่าง ค่าเวลาทั้งหมด (30 วินาที · 2 นาที · 5 นาที · 1 นาที · 10 วินาที · 8 วินาที) มาจาก config ไม่ใช่ค่าคงที่ในหน้าจอ
6 · แถบดีบักและแผงทดสอบ
แถบดีบัก 34px อยู่ล่างสุดของทุกสถานะ อ่านค่าแปดค่า: NET (มีเน็ตหรือไม่) · SRV (เวลาตอบของส่วนกลาง) · TUN (ไอพีในทันเนล) · UTC · UP (เวลาที่เครื่องเปิดมา) · GW · FW (เวอร์ชันเฟิร์มแวร์) · STATE ช่างที่เดินถึงตู้ต้องวินิจฉัยได้จากแถบนี้โดยไม่ต้องต่อเครื่องมืออื่น
แผงทดสอบอยู่นอกกรอบจอ เสมอ เพื่อไม่ให้ปุ่มทดสอบปนกับสิ่งที่คนขับเห็นจริง และปิดไว้เป็นค่าเริ่มต้น เปิดได้จากตัวเลือก showDevPanel เมื่อปิดแผง หัวจ่ายที่แสดงมาจากตัวเลือก deviceCode ซึ่งค่าเริ่มต้นคือ DP-0005
| อยากเห็นสถานะ |
ทำอย่างไร |
| #0 · #1 | เลือก DP-0005 (ว่างและเปิดจ่าย) แล้วกดรีบูตที่แผงทดสอบ |
| #2 | เลือก DP-0003 — มีคำขอ REQ-4846 จองอยู่ (ไม่มีกำหนดเวลา) กด “ตั้งเวลา 2 นาที” เพื่อดูการนับถอยหลังและการหมดเวลา |
| #3 | เลือก DP-0004 — REQ-4845 ผูกไว้แล้ว · กด “ตั้งเวลา 5 นาที” เพื่อดูการยกเลิกเมื่อไม่เริ่มเติม |
| #4 · #5 | ที่ DP-0001 (REQ-4844 กำลังเติม) กดเริ่มมาตรวัด · ปรับอัตราไหล · กดถึงเพดานหรือหยุดจ่ายเพื่อดูใบสรุป |
| #6 | ขณะอยู่ที่ #2/#3/#4 กด “ยกเลิกจากส่วนกลาง” ในแผงจำลองแอปคนขับ |
| #7 | ขณะอยู่ที่ #4 ปิดสวิตช์ server — ต้องเห็นป้ายเหลืองและจ่ายต่อได้ ไม่ตกไป #9 |
| #8 | เลือก DP-0006 (ปิดการจ่ายไว้) · หรือกดสวิตช์ปิดจ่ายระหว่าง #4 เพื่อยืนยันว่าไม่บังหน้าจอที่กำลังจ่าย |
| #9 | ที่หัวจ่ายว่าง ปิดสวิตช์ server — QR ต้องหายไป |
| #10 | เลือก DP-0002 (REQ-4847 ค้างที่ 18.75 ล.) แล้วกด “จำลองไฟดับ” |
ตารางที่ 3 — วิธีเข้าถึงทุกสถานะสำหรับทีม QA ปุ่มที่แผงทดสอบเปลี่ยนเงื่อนไขจริง ไม่ใช่การกระโดดข้ามหน้าจอ ผลที่เห็นจึงเป็นผลของกฎเดียวกับระบบจริง
7 · ข้อกำหนดที่ห้ามละเมิด
อ่านอย่างเดียว — ไม่มีปุ่มยกเลิกที่ตู้ การปล่อยงานเกิดจากแอปคนขับ หลังบ้าน หรือการหมดเวลาเท่านั้น
ไม่มีตัวเลขความจุถัง — ทั้งจอและทุกสถานะ เพดานถูกบังคับใช้อย่างเงียบ
ไม่มีการเลื่อนจอ — ทุกสถานะพอดี 1024 × 600 แม้หัวจ่ายมีหัวย่อย 4 หัว แถบข้อมูลด้านขวาเลื่อนได้เฉพาะกรณีหัวจ่ายมีข้อมูลมากผิดปกติ
ไม่มีภาพเคลื่อนไหว — ยกเว้นตัวเลขมาตรวัดที่เดินจริงและแถบความคืบหน้า สถานะเปลี่ยนทันที เพื่อไม่ให้ใครสงสัยว่าค่าที่เห็นเป็นค่าปัจจุบันหรือไม่
รหัส 6 หลักตรวจที่ส่วนกลาง — ไม่ตรวจที่หัวจ่าย และไม่มีช่วงผ่อนผันข้ามหน้าต่างเวลา นาฬิกาเครื่องคลาดเกิน 5 วินาทีต้องขึ้นคำเตือน
ภาษา — ไทยทุกอย่างที่คนขับอ่าน · อังกฤษ mono สำหรับแถบดีบัก คีย์สถานะ และแผงทดสอบ · เรียกรถว่า “รถน้ำมันเคลื่อนที่”
ตารางที่ 4 — ข้อกำหนดหกข้อที่มาจากสภาพหน้างาน ไม่ใช่รสนิยมการออกแบบ ทุกข้อมีเคสทดสอบกำกับใน Tool - Test Case (KIOSK-01…KIOSK-19)